home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / hplip / prnt / cups.py < prev    next >
Encoding:
Python Source  |  2007-04-04  |  15.4 KB  |  477 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Author: Don Welch
  20. #
  21.  
  22. # Std Lib
  23. import os, os.path, gzip
  24. import re, time, urllib, tempfile, glob
  25.  
  26. # Local
  27. from base.g import *
  28. from base import utils
  29.  
  30. # Handle case where cups.py (via device.py) is loaded
  31. # and cupsext doesn't exist yet. This happens in the
  32. # installer...
  33. try:
  34.     import cupsext
  35. except ImportError:
  36.     pass
  37.  
  38. nickname_pat = re.compile(r'''\*NickName:\s*\"(.*)"''', re.MULTILINE)
  39.  
  40. IPP_PRINTER_STATE_IDLE = 3
  41. IPP_PRINTER_STATE_PROCESSING = 4
  42. IPP_PRINTER_STATE_STOPPED = 5
  43.  
  44. PPD_UI_BOOLEAN = 0   # True or False option
  45. PPD_UI_PICKONE = 1   # Pick one from a list
  46. PPD_UI_PICKMANY = 2  # Pick zero or more from a list
  47.  
  48. # Non-std
  49. UI_SPINNER = 100           # Simple spinner with opt. suffix (ie, %)
  50. UI_UNITS_SPINNER = 101     # Spinner control w/pts, cm, in, etc. units
  51. UI_BANNER_JOB_SHEETS = 102 # dual combos for banner job-sheets
  52.  
  53. # ipp_op_t
  54. IPP_PAUSE_PRINTER = 0x0010
  55. IPP_RESUME_PRINTER = 0x011
  56. IPP_PURGE_JOBS = 0x012
  57. CUPS_GET_DEFAULT = 0x4001
  58. CUPS_GET_PRINTERS = 0x4002
  59. CUPS_ADD_MODIFY_PRINTER = 0x4003
  60. CUPS_DELETE_PRINTER = 0x4004
  61. CUPS_GET_CLASSES = 0x4005
  62. CUPS_ADD_MODIFY_CLASS = 0x4006
  63. CUPS_DELETE_CLASS = 0x4007
  64. CUPS_ACCEPT_JOBS = 0x4008
  65. CUPS_REJECT_JOBS = 0x4009
  66. CUPS_SET_DEFAULT = 0x400a
  67. CUPS_GET_DEVICES = 0x400b
  68. CUPS_GET_PPDS = 0x400c
  69. CUPS_MOVE_JOB = 0x400d
  70. CUPS_AUTHENTICATE_JOB = 0x400e
  71.  
  72. # ipp_jstate_t
  73. IPP_JOB_PENDING = 3    # Job is waiting to be printed
  74. IPP_JOB_HELD = 4       # Job is held for printing
  75. IPP_JOB_PROCESSING = 5 # Job is currently printing
  76. IPP_JOB_STOPPED = 6    # Job has been stopped
  77. IPP_JOB_CANCELLED = 7  # Job has been cancelled
  78. IPP_JOB_ABORTED = 8    # Job has aborted due to error
  79. IPP_JOB_COMPLETED = 8  # Job has completed successfully
  80.  
  81. # ipp_status_e
  82. IPP_OK = 0x0000 # successful-ok 
  83. IPP_OK_SUBST = 0x001 # successful-ok-ignored-or-substituted-attributes 
  84. IPP_OK_CONFLICT = 0x002 # successful-ok-conflicting-attributes 
  85. IPP_OK_IGNORED_SUBSCRIPTIONS = 0x003 # successful-ok-ignored-subscriptions 
  86. IPP_OK_IGNORED_NOTIFICATIONS = 0x004 # successful-ok-ignored-notifications 
  87. IPP_OK_TOO_MANY_EVENTS = 0x005 # successful-ok-too-many-events 
  88. IPP_OK_BUT_CANCEL_SUBSCRIPTION = 0x006 # successful-ok-but-cancel-subscription 
  89. IPP_OK_EVENTS_COMPLETE = 0x007 # successful-ok-events-complete 
  90. IPP_REDIRECTION_OTHER_SITE = 0x300
  91. IPP_BAD_REQUEST = 0x0400 # client-error-bad-request 
  92. IPP_FORBIDDEN = 0x0401 # client-error-forbidden 
  93. IPP_NOT_AUTHENTICATED = 0x0402 # client-error-not-authenticated 
  94. IPP_NOT_AUTHORIZED = 0x0403 # client-error-not-authorized 
  95. IPP_NOT_POSSIBLE = 0x0404 # client-error-not-possible 
  96. IPP_TIMEOUT = 0x0405 # client-error-timeout 
  97. IPP_NOT_FOUND = 0x0406 # client-error-not-found 
  98. IPP_GONE = 0x0407 # client-error-gone 
  99. IPP_REQUEST_ENTITY = 0x0408 # client-error-request-entity-too-large 
  100. IPP_REQUEST_VALUE = 0x0409 # client-error-request-value-too-long 
  101. IPP_DOCUMENT_FORMAT = 0x040a # client-error-document-format-not-supported 
  102. IPP_ATTRIBUTES = 0x040b # client-error-attributes-or-values-not-supported 
  103. IPP_URI_SCHEME = 0x040c # client-error-uri-scheme-not-supported 
  104. IPP_CHARSET = 0x040d # client-error-charset-not-supported 
  105. IPP_CONFLICT = 0x040e # client-error-conflicting-attributes 
  106. IPP_COMPRESSION_NOT_SUPPORTED = 0x040f # client-error-compression-not-supported 
  107. IPP_COMPRESSION_ERROR = 0x0410 # client-error-compression-error 
  108. IPP_DOCUMENT_FORMAT_ERROR = 0x0411 # client-error-document-format-error 
  109. IPP_DOCUMENT_ACCESS_ERROR = 0x0412 # client-error-document-access-error 
  110. IPP_ATTRIBUTES_NOT_SETTABLE = 0x0413 # client-error-attributes-not-settable 
  111. IPP_IGNORED_ALL_SUBSCRIPTIONS = 0x0414 # client-error-ignored-all-subscriptions 
  112. IPP_TOO_MANY_SUBSCRIPTIONS = 0x0415 # client-error-too-many-subscriptions 
  113. IPP_IGNORED_ALL_NOTIFICATIONS = 0x0416 # client-error-ignored-all-notifications 
  114. IPP_PRINT_SUPPORT_FILE_NOT_FOUND = 0x0417 # client-error-print-support-file-not-found 
  115. IPP_INTERNAL_ERROR = 0x0500 # server-error-internal-error 
  116. IPP_OPERATION_NOT_SUPPORTED = 0x0501 # server-error-operation-not-supported 
  117. IPP_SERVICE_UNAVAILABLE = 0x0502 # server-error-service-unavailable 
  118. IPP_VERSION_NOT_SUPPORTED = 0x0503 # server-error-version-not-supported 
  119. IPP_DEVICE_ERROR = 0x0504 # server-error-device-error 
  120. IPP_TEMPORARY_ERROR = 0x0505 # server-error-temporary-error 
  121. IPP_NOT_ACCEPTING = 0x0506 # server-error-not-accepting-jobs 
  122. IPP_PRINTER_BUSY = 0x0507 # server-error-busy 
  123. IPP_ERROR_JOB_CANCELLED = 0x0508 # server-error-job-canceled 
  124. IPP_MULTIPLE_JOBS_NOT_SUPPORTED = 0x0509 # server-error-multiple-document-jobs-not-supported 
  125. IPP_PRINTER_IS_DEACTIVATED = 0x050a # server-error-printer-is-deactivated 
  126.  
  127. CUPS_ERROR_BAD_NAME = 0x0f00
  128. CUPS_ERROR_BAD_PARAMETERS = 0x0f01
  129.  
  130.  
  131.  
  132. def restartCUPS(): # must be root. How do you check for this?
  133.     os.system('killall -HUP cupsd')
  134.  
  135. def getPPDPath(addtional_paths=None):
  136.     """
  137.         Returns the CUPS ppd path (not the foomatic one under /usr/share/ppd).
  138.         Usually this is /usr/share/cups/model.
  139.     """
  140.     if addtional_paths is None:
  141.         addtional_paths = []
  142.  
  143.     search_paths = prop.ppd_search_path.split(';') + addtional_paths
  144.  
  145.     for path in search_paths:
  146.         ppd_path = os.path.join(path, 'cups/model')
  147.         if os.path.exists(ppd_path):
  148.             return ppd_path
  149.  
  150.  
  151. def getAllowableMIMETypes():
  152.     """
  153.         Scan all /etc/cups/*.convs files for allowable file formats.
  154.     """
  155.     files = glob.glob("/etc/cups/*.convs")
  156.  
  157.     allowable_mime_types = []
  158.  
  159.     for f in files:
  160.         #log.debug( "Capturing allowable MIME types from: %s" % f )
  161.         conv_file = file(f, 'r')
  162.  
  163.         for line in conv_file:
  164.             if not line.startswith("#") and len(line) > 1:
  165.                 try:
  166.                     source, dest, cost, prog =  line.split()
  167.                 except ValueError:
  168.                     continue
  169.  
  170.                 if source not in ('application/octet-stream', 'application/vnd.cups-postscript'):
  171.                     allowable_mime_types.append(source)
  172.  
  173.     # Add some well-known MIME types that may not appear in the .convs files
  174.     allowable_mime_types.append("image/x-bmp")
  175.     allowable_mime_types.append("text/cpp")
  176.  
  177.     return allowable_mime_types
  178.     
  179. def getPPDDescription(f):
  180.     if f.endswith('.gz'):
  181.         nickname = gzip.GzipFile(f, 'r').read(4096)
  182.     else:
  183.         nickname = file(f, 'r').read(4096)
  184.     
  185.     try:
  186.         desc = nickname_pat.search(nickname).group(1)
  187.     except AttributeError:
  188.         desc = ''
  189.         
  190.     return desc
  191.  
  192.  
  193. def getSystemPPDs():
  194.     major, minor, patch = getVersionTuple()
  195.     ppds = {} # {'ppd name' : 'desc', ...}
  196.  
  197.     if major == 1 and minor < 2:
  198.         log.debug("(CUPS 1.1.x) Searching for PPDs in: %s" % sys_cfg.dirs.ppd)
  199.  
  200.         for f in utils.walkFiles(sys_cfg.dirs.ppd, pattern="HP*ppd*;hp*ppd*", abs_paths=True):
  201.             desc = getPPDDescription(f)
  202.             ppds[f] = desc
  203.             log.debug("%s: %s" % (f, desc))
  204.  
  205.     else: # 1.2.x
  206.         log.debug("(CUPS 1.2.x) Getting list of PPDs using CUPS_GET_PPDS...")
  207.         ppd_dict = cupsext.getPPDList()
  208.         cups_ppd_path = getPPDPath() # usually /usr/share/cups/model
  209.         foomatic_ppd_path = sys_cfg.dirs.ppdbase # usually /usr/share/ppd
  210.  
  211.         if not foomatic_ppd_path or not os.path.exists(foomatic_ppd_path):
  212.             foomatic_ppd_path = '/usr/share/ppd'
  213.  
  214.         log.debug("CUPS PPD base path = %s" % cups_ppd_path)
  215.         log.debug("Foomatic PPD base path = %s" % foomatic_ppd_path)
  216.  
  217.         for ppd in ppd_dict:
  218.             if 'HP-' in ppd or 'HP_' in ppd and ppd_dict[ppd]['ppd-make'] == 'HP':
  219.                 desc = ppd_dict[ppd]['ppd-make-and-model']
  220.  
  221.                 # PPD files returned by CUPS_GET_PPDS (and by lpinfo -m)
  222.                 # can be relative to /usr/share/ppd/ or to 
  223.                 # /usr/share/cups/model/. Not sure why this is.
  224.                 # Here we will try both and see which one it is...
  225.                 path = os.path.join(foomatic_ppd_path, ppd)
  226.                 
  227.                 if not os.path.exists(path):
  228.                     path = os.path.join(cups_ppd_path, ppd)
  229.                     
  230.                     if not os.path.exists(path):
  231.                         path = ppd # foomatic: or some other driver
  232.  
  233.                 ppds[path] = desc
  234.                 log.debug("%s: %s" % (path, desc))
  235.  
  236.     return ppds
  237.  
  238.  
  239. def levenshtein_distance(a,b):
  240.     """
  241.     Calculates the Levenshtein distance between a and b.
  242.     Written by Magnus Lie Hetland.
  243.     """
  244.     n, m = len(a), len(b)
  245.     if n > m:
  246.         a,b = b,a
  247.         n,m = m,n
  248.  
  249.     current = range(n+1)
  250.     for i in range(1,m+1):
  251.         previous, current = current, [i]+[0]*m
  252.         for j in range(1,n+1):
  253.             add, delete = previous[j]+1, current[j-1]+1
  254.             change = previous[j-1]
  255.             if a[j-1] != b[i-1]:
  256.                 change = change + 1
  257.             current[j] = min(add, delete, change)
  258.  
  259.     return current[n]
  260.  
  261. number_pat = re.compile(r""".*?(\d+)""", re.IGNORECASE)
  262.  
  263. def getPPDFile(stripped_model, ppds):
  264.     """
  265.         Match up a model name to a PPD from a list of system PPD files.
  266.     """
  267.     log.debug("1st stage edit distance match")
  268.     mins = {}
  269.     eds = {}
  270.     min_edit_distance = sys.maxint
  271.  
  272.     for f in ppds:
  273.         t = os.path.basename(f).lower().replace('hp-', '').replace('-hpijs', '').\
  274.             replace('.gz', '').replace('.ppd', '').replace('hp_', '').replace('_series', '').\
  275.             replace('foomatic:', '').lower()
  276.  
  277.         eds[f] = levenshtein_distance(stripped_model, t)
  278.         log.debug("dist('%s', '%s') = %d" % (stripped_model, t, eds[f]))
  279.         min_edit_distance = min(min_edit_distance, eds[f])
  280.  
  281.     log.debug("Min. dist = %d" % min_edit_distance)
  282.  
  283.     for f in ppds:
  284.         if eds[f] == min_edit_distance:
  285.             for m in mins:
  286.                 if os.path.basename(m) == os.path.basename(f):
  287.                     break # File already in list possibly with different path (Ubuntu, etc)
  288.             else:
  289.                 mins[f] = ppds[f]
  290.  
  291.     log.debug(mins)
  292.  
  293.     if len(mins) > 1: # try pattern matching the model number
  294.         log.debug("2nd stage matching with model number")
  295.  
  296.         try:
  297.             model_number = number_pat.match(stripped_model).group(1)
  298.             model_number = int(model_number)
  299.         except AttributeError:
  300.             pass
  301.         except ValueError:
  302.             pass
  303.         else:
  304.             log.debug("model_number=%d" % model_number)
  305.             matches = {} #[]
  306.             for x in range(3): # 1, 10, 100
  307.                 factor = 10**x
  308.                 log.debug("Factor = %d" % factor)
  309.                 adj_model_number = int(model_number/factor)*factor
  310.                 number_matching, match = 0, ''
  311.  
  312.                 for m in mins:
  313.                     try:
  314.                         mins_model_number = number_pat.match(os.path.basename(m)).group(1)
  315.                         mins_model_number = int(mins_model_number)
  316.                         log.debug("mins_model_number= %d" % mins_model_number)
  317.                     except AttributeError:
  318.                         continue
  319.                     except ValueError:
  320.                         continue
  321.  
  322.                     mins_adj_model_number = int(mins_model_number/factor)*factor
  323.                     log.debug("mins_adj_model_number=%d" % mins_adj_model_number)
  324.                     log.debug("adj_model_number=%d" % adj_model_number)
  325.  
  326.                     if mins_adj_model_number == adj_model_number:
  327.                         log.debug("match")
  328.                         number_matching += 1
  329.                         matches[m] = ppds[m]
  330.                         log.debug(matches)
  331.  
  332.                     log.debug("***")
  333.  
  334.                 if len(matches):
  335.                     mins = matches
  336.                     break
  337.  
  338.     return mins
  339.  
  340.  
  341. #
  342. # cupsext wrappers
  343. #
  344.  
  345. def getDefaultPrinter():
  346.     return cupsext.getDefaultPrinter()
  347.  
  348. def setDefaultPrinter(printer_name):
  349.     return cupsext.setDefaultPrinter(printer_name)
  350.  
  351. def accept(printer_name):
  352.     return controlPrinter(printer_name, CUPS_ACCEPT_JOBS)
  353.  
  354. def reject(printer_name):
  355.     return controlPrinter(printer_name, CUPS_REJECT_JOBS)
  356.  
  357. def start(printer_name):
  358.     return controlPrinter(printer_name, IPP_RESUME_PRINTER)
  359.  
  360. def stop(printer_name):
  361.     return controlPrinter(printer_name, IPP_PAUSE_PRINTER)
  362.  
  363. def purge(printer_name):
  364.     return controlPrinter(printer_name, IPP_PURGE_JOBS)
  365.  
  366. def controlPrinter(printer_name, cups_op):
  367.     if cups_op in (CUPS_ACCEPT_JOBS, CUPS_REJECT_JOBS, IPP_PAUSE_PRINTER, IPP_RESUME_PRINTER, IPP_PURGE_JOBS):
  368.         return cupsext.controlPrinter(printer_name, cups_op)
  369.  
  370.     return 0;
  371.  
  372. def openPPD(printer):
  373.     if not printer:
  374.         return
  375.  
  376.     return cupsext.openPPD(printer)
  377.  
  378. def closePPD():
  379.     return cupsext.closePPD()
  380.  
  381. def getPPD(printer):
  382.     if not printer:
  383.         return
  384.  
  385.     return cupsext.getPPD(printer)
  386.  
  387. def getPPDOption(option):
  388.     return cupsext.getPPDOption(option)
  389.  
  390. def getPPDPageSize():
  391.     return cupsext.getPPDPageSize()
  392.  
  393. def getPrinters():
  394.     return cupsext.getPrinters()
  395.  
  396. def getJobs(my_job=0, completed=0):
  397.     return cupsext.getJobs(my_job, completed)
  398.  
  399. def getAllJobs(my_job=0):
  400.     return cupsext.getJobs(my_job, 0) + cupsext.getJobs(my_job, 1)
  401.  
  402. def getVersion():
  403.     return cupsext.getVersion()
  404.  
  405. def getVersionTuple():
  406.     return cupsext.getVersionTuple()
  407.  
  408. def getServer():
  409.     return cupsext.getServer()
  410.  
  411. def cancelJob(jobid, dest=None):
  412.     if dest is not None:
  413.         return cupsext.cancelJob(dest, jobid)
  414.     else:
  415.         jobs = cupsext.getJobs(0, 0)
  416.         for j in jobs:
  417.             if j.id == jobid:
  418.                 return cupsext.cancelJob(j.dest, jobid)
  419.  
  420.     return False
  421.  
  422. def resetOptions():
  423.     return cupsext.resetOptions()
  424.  
  425. def addOption(option):
  426.     return cupsext.addOption(option)
  427.  
  428. def getOptions():
  429.     return cupsext.getOptions()
  430.  
  431. def printFile(printer, filename, title):
  432.     if os.path.exists(filename):
  433.         return cupsext.printFileWithOptions(printer, filename, title)
  434.     else:
  435.         return -1
  436.  
  437. def addPrinter(printer_name, device_uri, location, ppd_file, model, info):
  438.     log.debug("addPrinter('%s', '%s', '%s', '%s', '%s', '%s')" %
  439.         ( printer_name, device_uri, location, ppd_file, model, info))
  440.  
  441.     if ppd_file and not os.path.exists(ppd_file):
  442.         log.error("PPD file '%s' not found." % ppd_file)
  443.         return (-1, "PPD file not found")
  444.  
  445.     return cupsext.addPrinter(printer_name, device_uri, location, ppd_file, model, info)
  446.  
  447. def delPrinter(printer_name):
  448.     return cupsext.delPrinter(printer_name)
  449.  
  450. def getGroupList():
  451.     return cupsext.getGroupList()
  452.  
  453. def getGroup(group):
  454.     return cupsext.getGroup(group)
  455.  
  456. def getOptionList(group):
  457.     return cupsext.getOptionList(group)
  458.  
  459. def getOption(group, option):
  460.     return cupsext.getOption(group, option)
  461.  
  462. def getChoiceList(group, option):
  463.     return cupsext.getChoiceList(group, option)
  464.  
  465. def getChoice(group, option, choice):
  466.     return cupsext.getChoice(group, option, choice)
  467.  
  468. def setOptions():
  469.     return cupsext.setOptions()
  470.  
  471. def removeOption(option):
  472.     return cupsext.removeOption(option)
  473.  
  474. def setPasswordCallback(func):
  475.     return cupsext.setPasswordCallback(func)
  476.     
  477.